#include "PatternList.h"
#include "Pattern.h"
#include <iostream>
#include <fstream>
#include "Defines.h"
#include "Seq.h"
#include "Config.h"
#include "Common.h"

using namespace std;

CPatternList * CPatternList::m_pInstance = NULL;

CPatternList::CPatternList()
{
	m_pInstance = NULL;
	m_pvecPattern = new vector<CPattern*>();
	m_pvecUnpattern = new vector<CPos>();

	// TODO Move these unpatterned thing somewhere
	memset( m_caCoff, 0, REF_PIXEL_NUMBER * sizeof( char ) );
	m_caCoff[5] = m_caCoff[12] = -4;
	m_caCoff[16] = m_caCoff[19] = 15;


}

CPatternList::~CPatternList()
{
	for ( vector<CPattern*>::iterator i=m_pvecPattern->begin(); i!=m_pvecPattern->end(); i++ )
	{
		delete *i;
	}

	delete m_pvecPattern;
	delete m_pvecUnpattern;
}

CPatternList * CPatternList::GetInstance()
{
	if ( m_pInstance == NULL )
	{
		m_pInstance = new CPatternList();
	}

	return m_pInstance;
}

bool CPatternList::InitPatternListFromFile( string filename )
{
	fstream infile;
	infile.open( filename.c_str(), ios::in );
	if ( !infile.is_open() )
	{
		return false;
	}

	int temp;

	int count = 0;
	char pattern_array[REF_PIXEL_NUMBER];
	char coff_array[REF_PIXEL_NUMBER];
	while( !infile.eof() )
	{
		infile >> temp;
		infile.get();
		if ( count <REF_PIXEL_NUMBER )
		{
			pattern_array[count] = temp;
		}
		else
		{
			coff_array[count-REF_PIXEL_NUMBER] = temp;
		}

		count++;
		if ( count >= 40 )
		{
			count = 0;
			CPattern * pattern = new CPattern( pattern_array, coff_array, CConfig::GetConfig()->pattern_mask );
			// pattern->Dump();
			m_pvecPattern->push_back( pattern );
		}
	}

	infile.close();
	return true;

}

bool CPatternList::DoMatchRefPixelArray( unsigned char * ref_pixel_array, int frame, int x, int y )
{

	unsigned int sum = 0;
	unsigned int max = 0;
	unsigned int min = 256;
	char pattern_array[REF_PIXEL_NUMBER];
	bool match = false;
	unsigned int pattern_mask = CConfig::GetConfig()->pattern_mask;

	bool flat = CheckAreaFlat( ref_pixel_array );

	if ( flat ) 
	{
		// Flat Area, will be put into the unpattern vector
		// memset( pattern_array, 0, REF_PIXEL_NUMBER*sizeof( unsigned char ) );
	}
	else
	{
		// Binarization
		BinarizeRefPixelArray( pattern_array, ref_pixel_array );

		vector<CPattern*>::iterator i = m_pvecPattern->begin();
		for ( ; i!=m_pvecPattern->end(); i++ )
		{
			if ( (*i)->DoMatch( pattern_array, CPos( frame, x, y ) ) )
			{
				match = true;
				break;
			}
		}

	}

	if ( !match )
	{
		// record all the unpatterned pixels
		m_pvecUnpattern->push_back( CPos( frame, x, y ) );
		return false;
	}

	return true;
}


void CPatternList::Dump()
{
	vector<CPattern*>::iterator i = m_pvecPattern->begin();
	for ( ; i!=m_pvecPattern->end(); i++ )
	{
		(*i)->Dump( true );
	}
}

void CPatternList::DumpForPatterns()
{
	vector<CPattern*>::iterator i = m_pvecPattern->begin();
	for ( ; i!=m_pvecPattern->end(); i++ )
	{
		(*i)->Dump( false );
	}
}

bool CPatternList::InitPatternListFromSeq()
{

	CConfig * config = CConfig::GetConfig();

	CSeq * seq = config->seq;
	unsigned char ref_pixel_array[REF_PIXEL_NUMBER];
	int pattern_count = 0; 
	int unpattern_count = 0;

	unsigned int max = 0;
	unsigned int min = 256;
	char pattern_array[REF_PIXEL_NUMBER];
	bool match = false;
	char coff_array[REF_PIXEL_NUMBER];
	memset( coff_array, 0, sizeof(char) * REF_PIXEL_NUMBER );

	for ( int frame=0; frame<seq->m_iFrameCount; frame++ )
	{
		for( int y=VERTICAL_SKIP_COUNT; y<seq->m_iHeight-VERTICAL_SKIP_COUNT; y++ )
		{
			for ( int x=HORIZONTAL_SKIP_COUNT; x<seq->m_iWidth-HORIZONTAL_SKIP_COUNT; x+=2 )
			{
				max = 0;
				min = 256;
				match = false;

				GetRefPixelArray( x, y, ref_pixel_array, seq->m_ppRecPixelArray[frame], seq->m_iWidth, seq->m_iHeight );

				bool flat = CheckAreaFlat( ref_pixel_array );

				if ( flat )
				{
					// Flat Area 
					unpattern_count++;
				}
				else
				{
					// Binarization
					BinarizeRefPixelArray( pattern_array, ref_pixel_array );

					vector<CPattern*>::iterator i = m_pvecPattern->begin();
					for ( ; i!=m_pvecPattern->end(); i++ )
					{
						if ( (*i)->DoMatch( pattern_array, CPos( frame, x, y ) ) )
						{
							match = true;
							break;
						}
					}

					if ( !match )
					{
						// Add a new pattern
						CPattern * new_pattern = new CPattern( pattern_array, coff_array, config->pattern_mask );
						new_pattern->DoMatch( pattern_array, CPos( frame, x, y ) );
						m_pvecPattern->push_back( new_pattern );
						
					}

					pattern_count++;
				}

			}
		}
	}

	cout << "pattern " << pattern_count << " unpattern " << unpattern_count << " total " << pattern_count+ unpattern_count << endl;

	return true;
}

